/*!
 * \file WTSObject.hpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader基础对象类定义文件
 */
#pragma once
#include <stdint.h>
#include <atomic>
// #include <boost/smart_ptr/detail/spinlock.hpp>  // Deprecated in newer Boost versions
#include <mutex>

#include "WTSMarcos.h"
#include "../Share/ObjectPool.hpp"
#include "../Share/SpinMutex.hpp"

NS_WTP_BEGIN

/*!
 * \brief WonderTrader基础对象类，提供引用计数和内存管理功能
 * 
 * \details 该类是WonderTrader框架中所有对象的基类，提供以下核心功能：
 *          - 原子引用计数：线程安全的对象生命周期管理
 *          - 自动内存管理：当引用计数为0时自动删除对象
 *          - 引用状态查询：检查对象的引用计数状态
 *          - 异常安全保证：在引用计数操作中提供异常安全
 *          
 *          所有继承自WTSObject的类都具备智能指针般的特性，
 *          可以安全地在多线程环境中使用，避免内存泄漏和悬空指针问题。
 * 
 * \note 对象创建时引用计数为1，需要手动调用release()来减少引用计数
 * 
 * \author Wesley
 * \date 2020/03/30
 */
class WTSObject
{
public:
	/*!
	 * \brief 默认构造函数
	 * 
	 * \details 初始化对象的引用计数为1，表示对象刚创建时有一个拥有者
	 */
	WTSObject() :m_uRefs(1){}
	
	/*!
	 * \brief 虚析构函数
	 * 
	 * \details 确保派生类能够正确析构，释放相关资源
	 */
	virtual ~WTSObject(){}

public:
	/*!
	 * \brief 增加对象引用计数
	 * 
	 * \details 原子性地增加引用计数，用于表示有新的拥有者持有该对象。
	 *          该操作是线程安全的，可以在多线程环境中安全调用。
	 * 
	 * \return 增加后的引用计数值
	 * 
	 * \note 每次调用retain()后都应该对应一个release()调用
	 */
	inline uint32_t		retain(){ return m_uRefs.fetch_add(1) + 1; }

	/*!
	 * \brief 减少对象引用计数并在必要时销毁对象
	 * 
	 * \details 原子性地减少引用计数，当引用计数降为0时自动删除对象。
	 *          该操作是线程安全的，并提供异常安全保证。
	 *          
	 *          销毁逻辑：
	 *          - 如果引用计数已经为0，直接返回
	 *          - 原子性地减少引用计数
	 *          - 如果减少后引用计数为0，则删除对象
	 *          - 所有操作都在try-catch块中，确保异常安全
	 * 
	 * \note 对象一旦被删除，就不能再访问该对象的任何成员
	 */
	virtual void	release()
	{
		if (m_uRefs == 0)
			return;

		try
		{
			uint32_t cnt = m_uRefs.fetch_sub(1);
			if (cnt == 1)
			{
				delete this;
			}
		}
		catch(...)
		{

		}
	}

	/*!
	 * \brief 检查对象是否只有一个引用
	 * 
	 * \details 判断当前对象的引用计数是否为1，这通常表示只有一个拥有者持有该对象。
	 *          这个信息对于某些优化操作很有用，比如决定是否可以直接修改对象而不需要复制。
	 * 
	 * \return true表示引用计数为1，false表示有多个引用
	 * 
	 * \note 在多线程环境中，返回值只代表调用瞬间的状态，可能立即失效
	 */
	inline bool			isSingleRefs() { return m_uRefs == 1; }

	/*!
	 * \brief 获取当前引用计数
	 * 
	 * \details 返回对象当前的引用计数值，主要用于调试和监控目的
	 * 
	 * \return 当前引用计数值
	 * 
	 * \note 在多线程环境中，返回值只代表调用瞬间的状态
	 */
	inline uint32_t		retainCount() { return m_uRefs; }

protected:
	volatile std::atomic<uint32_t>	m_uRefs;	//原子引用计数器
};

/*!
 * \brief 带对象池优化的WonderTrader基础对象类模板
 * 
 * \details 该模板类继承自WTSObject，为频繁创建和销毁的对象提供对象池优化：
 *          - 线程局部对象池：每个线程维护独立的对象池，避免线程竞争
 *          - 重用机制：对象销毁时返回对象池而不是真正删除
 *          - 内存效率：减少内存分配和释放的开销
 *          - 线程安全：使用自旋锁保护对象池操作
 *          
 *          适用于高频创建销毁的小对象，可以显著提升性能
 * 
 * \tparam T 要池化的具体对象类型，必须继承自WTSPoolObject<T>
 * 
 * \note 使用对象池的对象需要确保构造和析构操作是幂等的
 * 
 * \author Wesley
 * \date 2020/03/30
 */
template<typename T>
class WTSPoolObject : public WTSObject
{
private:
	typedef ObjectPool<T> MyPool;	//对象池类型定义
	MyPool*			_pool;			//指向对象池的指针
	SpinMutex*	_mutex;				//指向保护对象池的自旋锁

public:
	/*!
	 * \brief 默认构造函数
	 * 
	 * \details 初始化对象池指针为NULL，实际的对象池分配在allocate()方法中进行
	 */
	WTSPoolObject():_pool(NULL){}
	
	/*!
	 * \brief 虚析构函数
	 * 
	 * \details 确保派生类能够正确析构
	 * 
	 * \note 实际的对象回收在release()方法中处理
	 */
	virtual ~WTSPoolObject() {}

public:
	/*!
	 * \brief 从对象池分配对象的静态工厂方法
	 * 
	 * \details 使用线程局部存储的对象池来分配对象，实现步骤：
	 *          1. 获取线程局部的对象池和互斥锁
	 *          2. 加锁保护对象池操作
	 *          3. 从对象池构造或重用对象
	 *          4. 解锁并设置对象的池指针和锁指针
	 *          5. 返回可用的对象指针
	 * 
	 * \return 从对象池分配的对象指针，引用计数为1
	 * 
	 * \note 返回的对象需要调用release()来回收到对象池
	 */
	static T*	allocate()
	{
		thread_local static MyPool		pool;	//线程局部对象池
		thread_local static SpinMutex	mtx;	//线程局部自旋锁

		mtx.lock();
		T* ret = pool.construct();
		mtx.unlock();
		ret->_pool = &pool;
		ret->_mutex = &mtx;
		return ret;
	}

public:
	/*!
	 * \brief 重写release方法，将对象归还给对象池
	 * 
	 * \details 重写基类的release方法，当引用计数降为0时不删除对象，
	 *          而是将对象归还给对象池以供重用：
	 *          1. 检查引用计数是否为0，为0则直接返回
	 *          2. 原子性地减少引用计数
	 *          3. 如果引用计数降为0，将对象归还给对象池
	 *          4. 使用互斥锁保护对象池操作
	 *          5. 提供异常安全保证
	 * 
	 * \note 对象归还给对象池后可能会被重用，不应再访问对象内容
	 */
	virtual void release() override
	{
		if (m_uRefs == 0)
			return;

		try
		{
			uint32_t cnt = m_uRefs.fetch_sub(1);
			if (cnt == 1)
			{
				_mutex->lock();
				_pool->destroy((T*)this);
				_mutex->unlock();
			}
		}
		catch (...)
		{

		}
	}
};
NS_WTP_END
